﻿#include "TestWindow.h"
#include <QFileDialog>
#include <QSize>
#include <QMessageBox>

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
}

TestWindow::TestWindow(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	this->setWindowTitle("OpenGL+FFMPEG渲染AVFrame数据");
	setAttribute(Qt::WA_DeleteOnClose, true);  // 关闭时自动销毁窗口
	timer = new QTimer();
	connect(timer, &QTimer::timeout, this, &TestWindow::OnTimeout);
	timer->setInterval(40);//设置定时间隔
	timer->start();//启动定时器
}


/// <summary>
/// C++ Qt + ffmpeg + openg渲染视频，总是频繁的崩溃。
///现已查明原因：OpenGL还没渲染完成TimeOut函数刷新就开始了。
///需要想一个办法让OpenGL渲染完成后再进行timeout，一帧一帧的来
/// 虽然找到了上述问题，但是又引申出了一个新的问题。ps：待调试解决
/// </summary>
void TestWindow::OnTimeout()
{
	qDebug() << "isDrawEnd()->" << ui.video->isDrawEnd();
	//std::unique_lock<std::mutex> lock(m_mutex);
	if (ui.video->isDrawEnd())
	{
		qDebug() << "OnTimeout->Init";
		auto frame = frameList.Pop();
		if (frame)
		{
			qDebug() << "OnTimeout->exec start";
			ui.video->Repaint(frame);
			qDebug() << "OnTimeout->exec end";
		}
	}
	else {
		qDebug() << "OpenGL未绘制完成，等待中....";
	}
	
}

void TestWindow::onSelectedFile()
{
	QString filter = "所有文件(*.*)"; //文件过滤器
	QString filePath = QFileDialog::getOpenFileName(this, "选择文件输出目录", "", filter);
	this->filePath = filePath;
	this->ui.outputPathEdit->setText(this->filePath);
}

void TestWindow::onStartPlayVideo()
{

	if (this->filePath.isEmpty()) {
		QMessageBox::information(this, "温馨提示", "请选择视频文件");
		return;
	}
	isRunning = true;
	connect(this, &TestWindow::updateUi, this, &TestWindow::OnUpdateUi, Qt::BlockingQueuedConnection);//QueuedConnection

	//封装/解封装器
	demuxer = new YDemuxer();
	//编码/解码器
	decoder = new YDecoder();

	///////////封装及解封装////////////////////
	auto ic = demuxer->Open(this->filePath.toStdString().c_str());
	demuxer->setContext(ic);
	int videoWidth = demuxer->GetVideoWidth();
	int videoHeight = demuxer->GetVideoHeight();

	ui.video->Init(videoWidth, videoHeight);

	///////////解码及编码////////////////////
	auto deContext = decoder->Create(demuxer->GetVideoCodecId(), false);
	decoder->setContext(deContext);
	//设置解码器参数
	demuxer->CopyParaParameters(demuxer->GetVideoIndex(), deContext);
	decoder->Open();

	renderThread = std::make_unique<std::thread>(&TestWindow::OnStartPlay, this);
}
void TestWindow::OnUpdateUi(AVFrame* frame)
{
	ui.video->Repaint(frame);
}

void TestWindow::OnStartPlay()
{

	AVPacket pkt;
	while (isRunning)
	{
		if (!demuxer->Read(&pkt))break;

		if (pkt.stream_index == demuxer->GetVideoIndex())
		{

			if (decoder->Send(&pkt))
			{
				auto frame = decoder->CreateFrame();
				while (decoder->Receive(frame))
				{
					//在子线程中渲染，感觉也没啥问题（因为此处并不涉及到OpenGL的渲染部分，只涉及到数据填充部分）。
					// 和其他渲染方式一样，都有内存冲突的问题
					//ui.video->Repaint(frame);

					//emit updateUi(av_frame_clone(frame));//此处发射信号会出现线程冲突的问题
					//frame_ = frame;
					//std::this_thread::sleep_for(std::chrono::milliseconds(40));
					// 
					if (frameList.Size() > 20)
					{
						MSleep(100);
						continue;
					}
					//frameList.Push(frame);
					frameList.Push(av_frame_clone(frame));
					//播放不带视频的音频
					qDebug() << "AVFrame已解码成功";
					//av_frame_unref(frame);
				}
				//av_frame_free(&frame);

			}
		}
		else {
			av_packet_unref(&pkt);
		}
	}

	qDebug() << "解封装结束";
}

void TestWindow::Release()
{
	if (isRunning)
	{
		isRunning = false;
		renderThread->join();
	}
	if (demuxer) {
		demuxer->Close();
		delete demuxer;
	}

	if (videoReScaler)
	{
		videoReScaler->Release();
		delete videoReScaler;
		videoReScaler = nullptr;
	}

	if (decoder)
	{
		delete decoder;
		decoder = nullptr;
	}
	frameList.Clear();
	if (timer)
	{
		timer->stop();
		delete timer;
		timer = nullptr;
	}

}

void TestWindow::closeEvent(QCloseEvent* event) {
	event->accept();  // 接受关闭事件（允许关闭）
	Release();
	qDebug() << "窗口已关闭";
}

TestWindow::~TestWindow()
{
}
